package com.interview.item.javabase.reflection;

import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Random;

import static com.interview.item.javabase.reflection.MainTest.test2;
import static com.interview.item.javabase.reflection.MainTest.test3;

/**
 * 反射-demo
 * 理解Class类并获取Class实例
 * 创建运行时类的对象
 * 调用运行时类的指定结构
 *
 * 笔记，见：印象笔记
 * 反射-Java具有动态语言特性、透视对象功能(通过Class、Filed、Method、Constructor等Java.lang.reflect的API实现)
 * 调用私有属性，要使用getDeclaredXX方法，filed.setAccessible(true)
 * @author: zhangxiaohu@souche.com
 * @date: 2022/9/19
 */
public class ReflectionTest {
    public static void main(String[] args) throws Exception {
        test2();
        System.out.println("--------------");
        test3();
        System.out.println("--------------");
        Class<?> aClass1 = Class.forName("java.lang.Object");
        //获取该类中所有方法
        Method[] declaredMethods = aClass1.getDeclaredMethods();
        System.out.println(declaredMethods.length);
        for (Method meth : declaredMethods) {
            System.out.println(meth);
        }
    }

}

class MainTest {
    public static void main(String[] args) throws Exception {
        //正常调用
        Person person = new Person();
        person.say();

        //读取配置文件中的类路径的字符串
        BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\ideaProject\\interview\\two\\interview-item\\javabase2\\src\\main\\resources\\config"));
        String classPath = bufferedReader.readLine();
        System.out.println(classPath);

        //1.用反射创建该类的对象
        Class<?> aClass = Class.forName(classPath);
        Object newInstance1 = aClass.newInstance();
        Person person1 = (Person) aClass.newInstance();
        //2.构造器反射调用，注：私有构造器调用不了
        Constructor constructor = aClass.getConstructor(String.class);
        Object con = constructor.newInstance("23name");
        System.out.println("constructor:"+con.toString());


        person1.say();
        System.out.println("使用Class对象方法比较："+(aClass.isInstance(person)));
        System.out.println("比较：----" + (newInstance1 instanceof Person));

        //3.方法反射调用,注意：调用say1私有方法,设置setAccessible权限
        Method say = aClass.getDeclaredMethod("say1",new Class[]{int.class,int.class});
        say.setAccessible(true);
        Object invoke = say.invoke(newInstance1, new Object[]{4, 5});
        System.out.println("输出Method:" + invoke);
        //4.属性反射调用,调用私有属性，要使用getDeclaredField方法
        Field age = aClass.getDeclaredField("age");
        age.setAccessible(true);
        //给字段赋值
        age.set(newInstance1,22);
        Object field = age.get(newInstance1);
        System.out.println("Field:"+field);

        Field age1 = aClass.getField("age1");
        age1.setAccessible(Boolean.TRUE);
        Object age2 = age1.get(newInstance1);
        System.out.println("Field2:"+age2);
    }

    /**
     * 体现反射的动态性
     *
     * @throws Exception
     */
    public static void test2() throws Exception {
        for (int i = 0; i < 10; i++) {
            //0,1,2
            int num = new Random().nextInt(3);
            String classPath = "";
            switch (num) {
                case 0:
                    classPath = "java.util.Date";
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "com.interview.item.javabase.reflection.Person";
                    break;
            }
            Class<?> aClass = Class.forName(classPath);
            Object newInstance = aClass.newInstance();
            System.out.println(newInstance.getClass().getName());
        }
    }

    /**
     * 获取一个类的Class对象的的四种方式
     *
     * @throws Exception
     */
    public static void test3() throws Exception {
        //@1.调用运行时类的属性
        Class class1 = Person.class;
        System.out.println("class1：" + class1);
        //@2.通过运行时类的对象，调用getClass()
        Person p1 = new Person();
        Class<? extends Person> class2 = p1.getClass();
        System.out.println("class2:" + class2);
        //@3.调用Class的静态方法forName
        Class<?> class3 = Class.forName("java.lang.Object");
        System.out.println("class3:" + class3);
        //@4.使用类的加载器ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class<?> class4 = classLoader.loadClass("java.lang.Readable");
        System.out.println("class4:" + class4);
    }
}

/**
 * 利用反射创建数组
 */
class TestArray{
    public static void main(String[] args)throws Exception {
        Class<?> aClass = Class.forName("java.lang.String");
        //Array类为java.lang.reflect.Array类,通过Array.newInstance()创建数组对象
        Object array = Array.newInstance(aClass, 10);
        //往数组里添加内容
        Array.set(array,0,"90");
        Array.set(array,2,"历史");
        Array.set(array,4,"9090");
        Array.set(array,8,"8sdf");
        System.out.println(Array.get(array,9));
    }
}